#include "lilanmangeclient.h"

quint16 LiLANMangeClient::allPort=2000;
quint32 LiLANMangeClient::allFileServerID=0;//用时加上是否超上限判断

LiLANMangeClient::LiLANMangeClient(QObject *parent) : QObject(parent)
{
    rootUdpPort=3000;
    multicastAddress="236.0.0.26";
    goalPort=3001;
    myName="KinectClient";
    textCode=QTextCodec::codecForName("UTF-8");

    rootUdpSocket=new QUdpSocket(this);
    rootUdpSocket->bind(QHostAddress::AnyIPv4,rootUdpPort,QUdpSocket::ReuseAddressHint);
    rootUdpSocket->setSocketOption(QAbstractSocket::MulticastLoopbackOption,0);//防止自己接受
//    224.0.1.0～238.255.255.255为用户可用的组播地址（临时组地址），全网范围内有效。
//    239.0.0.0～239.255.255.255为本地管理组播地址，仅在特定的本地范围内有效。
    rootUdpSocket->joinMulticastGroup(QHostAddress(multicastAddress));//加入组播地址
    connect(rootUdpSocket,SIGNAL(readyRead()),this,SLOT(onRootUdpNews()));


//可去除,为了发送信息通知客户端,但是,感觉应该通过外部控制,不必自控
    callServerTimer=new QTimer(this);
    callServerTimer->setSingleShot(false);
    connect(callServerTimer,SIGNAL(timeout()),this,SLOT(callServer()));
    callServerRange=new QTimer(this);
    callServerRange->setSingleShot(true);
    connect(callServerRange,SIGNAL(timeout()),this,SLOT(callServerTimerStop()));
    //******************************************************************

    serverRegistery=new QHash<QString,QString>;
    
    tcpNewsList=new QHash<qintptr,QString>;
    tcpSocketRegistery=new QHash<qintptr,LiTcpSocketString*>;
    tcpSocketFileRegistery=new QHash<qintptr,LiTcpSocketFileClient*>;
    tcpSocketFileServerRegistery=new QHash<quint32,LiTcpSocketFileServer*>;
    udpaClientRegistery=new QHash<QHostAddress*,quint16*>;
    udpGoalPortList=new QList<quint16>;
    localIPV4Address=getLocalIPAddress();


    connect(this,SIGNAL(updateServerRegistery()),this,SLOT(autoConnectServer()));
}

//端口号增加
void LiLANMangeClient::addAllPort()
{
    if(allPort<65535)
    {
        allPort++;
    }
    else {
        allPort=2000;
    }
}



//服务器在吗
void LiLANMangeClient::callServer()
{
    broadcastMessage("HelloServer|Name=="+myName+"|");
}

void LiLANMangeClient::callServerTimerStart(int cycle,int sustain)
{
    serverRegistery->clear();
    callServerTimer->start(cycle);
    callServerRange->start(sustain);
//    qDebug()<<"广播开始"<<endl;;;
    qDebug()<<"广播";

}

void LiLANMangeClient::callServerTimerStop()
{
    callServerTimer->stop();
    qDebug()<<"广播停止";
}

void LiLANMangeClient::onRootUdpNews()
{
    while (rootUdpSocket->hasPendingDatagrams()) {
        QByteArray datagram;
        datagram.resize(rootUdpSocket->pendingDatagramSize());
        senderAddress=new QHostAddress();
        rootUdpSocket->readDatagram(datagram.data(), datagram.size(),&senderAddress, &senderPort);
        tempRootStr=datagram.data();
        if(!udpaClientRegistery->contains(senderAddress))//电脑似乎只能对固定地址广播WIFI，无奈。
        {
            udpaClientRegistery->insert(senderAddress,&senderPort);
        }
        handleRootUdpNews(tempRootStr,*senderAddress);
        emit udpNews(tempRootStr);
        qDebug()<<"root接受"<<tempRootStr<<senderAddress<<senderPort;
    }
}

//添加广播对象
bool LiLANMangeClient::addBroadcastGoal(QString senderAddress, quint16 senderPort)
{
    bool contain=false;
    QHash<QHostAddress*,quint16*>::const_iterator index=udpaClientRegistery->constBegin();
    while(index!=udpaClientRegistery->constEnd())
    {
        if((index.key()->toString()==senderAddress)&&(*(index.value())==senderPort))
        {
            contain=true;
        }
        index++;
    }
    if(contain)
    {
        return false;
    }
    else
    {
        QHostAddress* tempHost=new QHostAddress(senderAddress);
        udpaClientRegistery->insert(tempHost,&senderPort);
        qDebug()<<"UdpAdd："<<senderAddress<<senderPort;
        return true;
    }
}
//添加广播端口
void LiLANMangeClient::addBroadcastPort(quint16 addPort)
{
    udpGoalPortList->append(addPort);
}

//broadcastMessage("HelloClient|Name=="+myName+"|Port=="+QString::number(serverPort())+"|");
void LiLANMangeClient::handleRootUdpNews(QString str, QHostAddress &sendAddress)
{
    if(str.startsWith("HelloClient"))
    {
        if(!serverRegistery->contains(sendAddress.toString()))
        {
            QString tempStr=str.section("|",1,2);//返回Name=="+myName+"|Port=="+QString::number(serverPort())
            serverRegistery->insert(sendAddress.toString(),tempStr);
//            qDebug()<<"C++服务器数："<<serverRegistery->count();
            emit updateServerRegistery();
        }
    }
}

//广播信息
void LiLANMangeClient::broadcastMessage(QString str)
{
    QByteArray data=textCode->fromUnicode(str);
    rootUdpSocket->writeDatagram(data,QHostAddress::Broadcast,goalPort);
    rootUdpSocket->writeDatagram(data,QHostAddress("192.168.155.255"),goalPort);
    rootUdpSocket->writeDatagram(data,QHostAddress(multicastAddress),goalPort);
    qDebug()<<str;
}

void LiLANMangeClient::broadcastMessageAllPort(QString str,QString address)
{
    QByteArray data=textCode->fromUnicode(str);
    for(int i=0;i<udpGoalPortList->size();++i)
    {
        rootUdpSocket->writeDatagram(data,QHostAddress(address),udpGoalPortList->at(i));
    }
}
void LiLANMangeClient::broadcastMessageAllAccurate(QString str)
{
    QByteArray data=textCode->fromUnicode(str);
    QHash<QHostAddress*,quint16*>::const_iterator index=udpaClientRegistery->constBegin();
    while(index!=udpaClientRegistery->constEnd())
    {
        rootUdpSocket->writeDatagram(data,*(index.key()),*(index.value()));
        index++;
    }
}


void LiLANMangeClient::broadcastMessageToOne(quint16 port,QString str)
{
    QByteArray data=textCode->fromUnicode(str);
    rootUdpSocket->writeDatagram(data,QHostAddress::Broadcast,port);
}


void LiLANMangeClient::broadcastMessageToOne(QString address,qint16 port,QString str)
{
    QByteArray data=textCode->fromUnicode(str);
    rootUdpSocket->writeDatagram(data,QHostAddress(address),port);
}

//连接
void  LiLANMangeClient::connectToServe(QString address, quint16 port)
{
    LiTcpSocketString *tempSocket=new LiTcpSocketString(tcpNewsList,this);
    tempSocket->connectToHost(QHostAddress(address),port);
    tempSocket->setGoalIPV4(address);
    connect(tempSocket,SIGNAL(connectSucceed(LiTcpSocketString*)),this,SLOT(onRegistTcpSocket(LiTcpSocketString*)));
    connect(tempSocket,SIGNAL(receiveNews(qintptr)),this,SLOT(onTcpNews(qintptr)));
}

void LiLANMangeClient::onRegistTcpSocket(LiTcpSocketString *succeedConnect)
{
    tcpSocketRegistery->insert(succeedConnect->socketDescriptor(),succeedConnect);
     connect(succeedConnect,SIGNAL(disconnectDescriptor(qintptr)),this,SLOT(onDeleteTcpSocketString(qintptr)));
    emit updateTcpSocketRegistery();
    registerTcpToGoal(succeedConnect);
}

void LiLANMangeClient::registerTcpToGoal(LiTcpSocketString *tcpsocket)
{
    sendTcpNews(tcpsocket,"RegistTcp|ID=="+QString::number(tcpsocket->socketDescriptor())+"|Name=="+myName+"|");
}

//初处理tcp信息
void LiLANMangeClient::onTcpNews(qintptr tcpSocketDescript)
{
    QHash<qintptr,QString>::const_iterator index=tcpNewsList->constBegin();
    while (!tcpNewsList->empty())
    {
        index=tcpNewsList->constBegin();
        //处理函数 index。key（） value（）
        handleTcpNews(index.key(),index.value());
//        qDebug()<<"tcp数据表"<<index.key()<<index.value();
        tcpNewsList->remove(index.key());
    }
}

//tcp消息发送
void LiLANMangeClient::sendTcpNews(LiTcpSocketString *tcpsocket, QString str)
{
    QByteArray bytest = textCode->fromUnicode(str);
    tcpsocket->write(bytest);
}

void LiLANMangeClient::sendTcpNews(int socketDescript, QString str)
{
    QByteArray bytest = textCode->fromUnicode(str);
    LiTcpSocketString *tempSocket=tcpSocketRegistery->value(socketDescript);
    tempSocket->write(bytest);
    qDebug()<<"asdIP"<<tempSocket->peerAddress()<<str;
//    QByteArray bytest = textCode->fromUnicode(str);
//    tcpSocketRegistery->value(socketDescript)->write(bytest);
}

void LiLANMangeClient::sendTcpNews(QString goalName, QString str)
{

    qDebug()<<"a///////////////////////////////////////////////////////////////////////////a";
    QByteArray bytest = textCode->fromUnicode(str);
    int tempint=returnDescriptorFromGoalName(goalName);
    if(tempint>0)
    {
        LiTcpSocketString *tempSocket=tcpSocketRegistery->value(tempint);
        tempSocket->write(bytest);
    }
    qDebug()<<"发:"<<str<<"给"<<goalName;
}


//文件tcp监听
//bool LiLANMangeClient::fileTcpListen(LiTcpSocketFileServer *tcpSocketFileServer, QHostAddress address, quint16 port)
//{
//    while(tcpSocketFileServer->serverPort()==0)
//    {
//        tcpSocketFileServer->listen(QHostAddress::AnyIPv4,allPort);
//        addAllPort();
//    }
//    qDebug()<<"Server绑定端口号："<<tcpSocketFileServer->serverPort();
//    emit debug("Server绑定端口号："+tcpSocketFileServer->serverPort());
//    return true;
//}
//文件发送
void LiLANMangeClient::sendTcpFile(QString fileName, LiTcpSocketString *tcpSocketStr)
{
    LiTcpSocketFileServer *tempTcpFile=new LiTcpSocketFileServer(this);
    addAllFileServerID();
    tempTcpFile->setID(allFileServerID);
    tcpSocketFileServerRegistery->insert(allFileServerID,tempTcpFile);
    sendTcpNews(tcpSocketStr,tempTcpFile->sendFileAggrement_One(fileName));
//    connect(tempTcpFile,SIGNAL(sendFileOver(quint32)),this,SLOT(onDeleteTcpSocketFileServer(quint32)));
}

void LiLANMangeClient::sendTcpFile(QString fileName, int tcpDescriptor)
{
    LiTcpSocketFileServer *tempTcpFile=new LiTcpSocketFileServer(this);
    addAllFileServerID();
    tempTcpFile->setID(allFileServerID);
    tcpSocketFileServerRegistery->insert(allFileServerID,tempTcpFile);
    sendTcpNews(tcpDescriptor,tempTcpFile->sendFileAggrement_One(fileName));
//    connect(tempTcpFile,SIGNAL(sendFileOver(quint32)),this,SLOT(onDeleteTcpSocketFileServer(quint32)));
}
//Tcp信息处理
void LiLANMangeClient::handleTcpNews(qintptr tcpSocketDescript, QString tcpNews)
{
    qDebug()<<"tcpnews:"<<tcpNews;
    emit debug(tcpNews+QString::number(tcpSocketDescript));
    //比赛要求
    emit tcpNewsKinect(tcpNews);
    //............
    if(tcpNews.startsWith(QLatin1String("File|")))
    {
        LiTcpSocketFileClient *tempTcpSocketFile=new LiTcpSocketFileClient(this);
        connect(tempTcpSocketFile,SIGNAL(returnMe(LiTcpSocketFileClient *)),this,SLOT(onRegistTcpSocketFile(LiTcpSocketFileClient*)));
        connect(tempTcpSocketFile,SIGNAL(receiveFileOver(qintptr)),this,SLOT(onDeleteTcpSocketFileClient(qintptr)));
        LiTcpSocketString *tempTcpSocketStr=(*tcpSocketRegistery)[tcpSocketDescript];
        tempTcpSocketFile->receiveFileAggrement_One(tcpNews,tempTcpSocketStr->peerAddress().toString());
    }
}

void LiLANMangeClient::onRegistTcpSocketFile(LiTcpSocketFileClient *fileTcpSocket)
{
    tcpSocketFileRegistery->insert(fileTcpSocket->socketDescriptor(),fileTcpSocket);
}

void LiLANMangeClient::addAllFileServerID()
{
    if(allFileServerID<65535)
    {
        while (tcpSocketFileServerRegistery->contains(allFileServerID)) {
            allFileServerID++;
        }
    }
    else
    {
        allFileServerID=0;
    }
}

//void LiLANMangeClient::onDeleteTcpSocketFileClient(qintptr socketDescript)
//{
//    LiTcpSocketFileClient *tempTcpSocketFileClient=(*tcpSocketFileRegistery)[socketDescript];
//    tempTcpSocketFileClient->deleteLater();
//    tcpSocketFileRegistery->remove(socketDescript);
//}

//void LiLANMangeClient::onDeleteTcpSocketFileServer(quint32 id)
//{
//    LiTcpSocketFileServer *tempTcpSocketFileServer=(*tcpSocketFileServerRegistery)[id];
//    tempTcpSocketFileServer->deleteLater();
//    tcpSocketFileServerRegistery->remove(id);
//}

//删除文件传输客户端
void LiLANMangeClient::onDeleteTcpSocketFileClient(qintptr socketDescript)
{
    LiTcpSocketFileClient *tempTcpSocketFileClient=(*tcpSocketFileRegistery)[socketDescript];
    receiveFileOver (tempTcpSocketFileClient->getFileSavePath ());
    tempTcpSocketFileClient->deleteLater();
    tcpSocketFileRegistery->remove(socketDescript);
}
//删除文件传输服务端
void LiLANMangeClient::onDeleteTcpSocketFileServer(quint32 id)
{
    LiTcpSocketFileServer *tempTcpSocketFileServer=(*tcpSocketFileServerRegistery)[id];
    tempTcpSocketFileServer->deleteLater();
    tcpSocketFileServerRegistery->remove(id);
}
//删除字符传输tcp套接字
void LiLANMangeClient::onDeleteTcpSocketString(qintptr socketDescript)
{
    LiTcpSocketString *tempTcpSocketString=(*tcpSocketRegistery)[socketDescript];
    tempTcpSocketString->deleteLater();
    tcpSocketRegistery->remove(socketDescript);
    emit updateTcpSocketRegistery();
    qDebug()<<"到底行不行";
}

//    返回本机IP地址
QString LiLANMangeClient::getLocalIPAddress()
{
    QString ipAddress;
        QList<QHostAddress> ipAddressesList = QNetworkInterface::allAddresses();
        for (int i = 0; i < ipAddressesList.size(); ++i) {
            if (ipAddressesList.at(i) != QHostAddress::LocalHost &&
                ipAddressesList.at(i).toIPv4Address()) {
                ipAddress = ipAddressesList.at(i).toString();
                break;
            }
        }
        if (ipAddress.isEmpty())
            ipAddress = QHostAddress(QHostAddress::LocalHost).toString();
        return ipAddress;
}







































//属性修改
int LiLANMangeClient::returnServerRegisteryCount()
{
    return serverRegistery->count();
}
QString LiLANMangeClient::returnServerRegisteryKey(int index)
{
    QList<QString> tempList=serverRegistery->keys();
    return tempList.at(index);
}
QString LiLANMangeClient::returnServerRegisteryValue(int index)
{
    QList<QString> tempList=serverRegistery->values();
    return tempList.at(index);
}
QString LiLANMangeClient::returnServerRegisteryName(int index)
{
    QString tempStr1=returnServerRegisteryValue(index);
    QString tempStr2=tempStr1.section("|",0,0);
    tempStr1=tempStr2.section("==",1,1);
    return tempStr1;
}
int LiLANMangeClient::returnServerRegisteryPort(int index)
{
    QString tempStr1=returnServerRegisteryValue(index);
    QString tempStr2=tempStr1.section("|",1,1);
    int tempInt=tempStr2.section("==",1,1).toInt();
    return tempInt;
}



int LiLANMangeClient::returnTcpSocketRegisteryCount()
{
    return tcpSocketRegistery->count();
}
int LiLANMangeClient::returnTcpSocketRegisteryKey(int index)
{
    QList<qintptr> tempList=tcpSocketRegistery->keys();
    return (int)(tempList.at(index));
}

void LiLANMangeClient::autoConnectServer()
{
    connectToServe(returnServerRegisteryKey(0),returnServerRegisteryPort(0));
}

//通过goalName查询其描述符,没有返回-1
int LiLANMangeClient::returnDescriptorFromGoalName(QString goalName)
{
    QHash<qintptr,LiTcpSocketString*>::const_iterator index=serverRegistery->constBegin();
    while(index!=tcpSocketRegistery->constEnd())
    {
        LiTcpSocketString *tempSocket=index.value();
        if(tempSocket->returnGoalName()==goalName)
        {
            return (int)index.key();
        }
        index++;
    }
    return -1;
}
